#include "W25Qxx.h"
#include "spi.h"
#include "gpio.h"

/*W25QXX指令集定义*/
#define W25X_WriteEnable 0x06
#define W25X_WriteDisable 0x04
#define W25X_ReadStatusReg1 0x05
#define W25X_PageProgram 0x02
#define W25X_SectorErase 0x20
#define W25X_ReadData 0x03
#define W25X_JedecDeviceID 0x9F

/*初始化函数*/
void w25qxx_init(void)
{
  uint8_t dummy = 0xFF;
  CS_HIGH();
  HAL_SPI_Transmit(&hspi1, &dummy, 1, 100);
}

/*写使能*/
void w25qxx_write_enable(void)
{
  uint8_t cmd = W25X_WriteEnable;
  CS_LOW();
  HAL_SPI_Transmit(&hspi1, &cmd, 1, 100);
  CS_HIGH();
}

/*读寄存器状态*/
uint8_t w25qxx_read_status_reg(void)
{
  uint8_t status;
  uint8_t cmd = W25X_ReadStatusReg1;
  CS_LOW();
  HAL_SPI_Transmit(&hspi1, &cmd, 1, 100);
  HAL_SPI_Receive(&hspi1, &status, 1, 100);
  CS_HIGH();
  return status;
}

/*等待FLASH空闲*/
void w25qxx_wait_busy(void)
{
  while (w25qxx_read_status_reg() & 0x01);//检测flash芯片
}

/*扇区擦除*/
void w25qxx_sector_erase(uint32_t addr)
{
  w25qxx_write_enable();
  CS_LOW();

  uint8_t cmd[4] =
      {
          W25X_SectorErase,
          (addr >> 16) & 0xFF, // 高位
          (addr >> 8) & 0xFF,  // 中位
          addr & 0xFF          // 低位
      };

  HAL_SPI_Transmit(&hspi1, cmd, 4, 100);
  CS_HIGH();
  w25qxx_wait_busy();
}

/*页写入*/
void w25qxx_pagewrite(uint32_t addr, uint8_t *data, uint16_t len)
{
  w25qxx_write_enable();
  CS_LOW();

  uint8_t cmd[4] =
      {
          W25X_PageProgram,
          (addr >> 16) & 0xFF,//高位
          (addr >> 8) & 0xFF,//中位
          addr & 0xFF        //低位
      };

  HAL_SPI_Transmit(&hspi1, cmd, 4, 100);//发送写命令和地址
  HAL_SPI_Transmit(&hspi1, data, len, 1000);//发送数据
  CS_HIGH();
  w25qxx_wait_busy();
}

/*读数据*/
void w25qxx_read(uint32_t addr, uint8_t *buf, uint16_t len)
{
  CS_LOW();

  uint8_t cmd[4] =
      {
          W25X_ReadData,
          (addr >> 16) & 0xFF,
          (addr >> 8) & 0xFF,
          addr & 0xFF
      };

  HAL_SPI_Transmit(&hspi1, cmd, 4, 100);//发送读命令和地址
  HAL_SPI_Receive(&hspi1, buf, len, 1000);//接收数据
  CS_HIGH();
}
